<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>Vue-响应式原理 | 小马过河</title>
    <meta name="generator" content="VuePress 1.8.2">
    <link rel="icon" href="/img/manong.jpg">
    <script src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"></script>
    <link rel="manifest" href="/manifest.json">
    <link rel="apple-touch-icon" href="/img/mxx-152-152.png">
    <meta name="description" content="本章为小马学习专栏——Vue响应式原理">
    <meta name="keywords" content="马新想 小马学习 vue 响应式原理">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
    <meta name="theme-color" content="#ededed">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="msapplication-TileColor" content="#000000">
    <meta name="msapplication-TileImage" content="/img/mxx-144.png">
    
    <link rel="preload" href="/assets/css/0.styles.154256f1.css" as="style"><link rel="preload" href="/assets/js/app.f1a8d465.js" as="script"><link rel="preload" href="/assets/js/2.5bab2b7d.js" as="script"><link rel="preload" href="/assets/js/102.27347aba.js" as="script"><link rel="prefetch" href="/assets/js/10.586b05b4.js"><link rel="prefetch" href="/assets/js/100.17640669.js"><link rel="prefetch" href="/assets/js/101.9c523894.js"><link rel="prefetch" href="/assets/js/103.37a029fe.js"><link rel="prefetch" href="/assets/js/104.1d8f728c.js"><link rel="prefetch" href="/assets/js/105.8081ec6e.js"><link rel="prefetch" href="/assets/js/11.28ad280e.js"><link rel="prefetch" href="/assets/js/12.5e108f27.js"><link rel="prefetch" href="/assets/js/13.3678126c.js"><link rel="prefetch" href="/assets/js/14.505a08b7.js"><link rel="prefetch" href="/assets/js/15.8f3c0c53.js"><link rel="prefetch" href="/assets/js/16.4256e6cb.js"><link rel="prefetch" href="/assets/js/17.17d3d968.js"><link rel="prefetch" href="/assets/js/18.73488ae7.js"><link rel="prefetch" href="/assets/js/19.9d056309.js"><link rel="prefetch" href="/assets/js/20.52185694.js"><link rel="prefetch" href="/assets/js/21.3b7e8437.js"><link rel="prefetch" href="/assets/js/22.4d4d8a8b.js"><link rel="prefetch" href="/assets/js/23.dac1a360.js"><link rel="prefetch" href="/assets/js/24.798b5147.js"><link rel="prefetch" href="/assets/js/25.16d30679.js"><link rel="prefetch" href="/assets/js/26.3e5e50ab.js"><link rel="prefetch" href="/assets/js/27.99e01b84.js"><link rel="prefetch" href="/assets/js/28.86b7c539.js"><link rel="prefetch" href="/assets/js/29.ea981f89.js"><link rel="prefetch" href="/assets/js/3.c22f362a.js"><link rel="prefetch" href="/assets/js/30.6c923d43.js"><link rel="prefetch" href="/assets/js/31.df940781.js"><link rel="prefetch" href="/assets/js/32.3e5a19c7.js"><link rel="prefetch" href="/assets/js/33.0936aa71.js"><link rel="prefetch" href="/assets/js/34.566820dc.js"><link rel="prefetch" href="/assets/js/35.e263f3e4.js"><link rel="prefetch" href="/assets/js/36.32ae1d3b.js"><link rel="prefetch" href="/assets/js/37.ac0fe1ce.js"><link rel="prefetch" href="/assets/js/38.5ff1b8eb.js"><link rel="prefetch" href="/assets/js/39.da39237f.js"><link rel="prefetch" href="/assets/js/4.dca68745.js"><link rel="prefetch" href="/assets/js/40.c92cf280.js"><link rel="prefetch" href="/assets/js/41.b2318f21.js"><link rel="prefetch" href="/assets/js/42.9e98acc0.js"><link rel="prefetch" href="/assets/js/43.6a890842.js"><link rel="prefetch" href="/assets/js/44.8c501675.js"><link rel="prefetch" href="/assets/js/45.a7b73149.js"><link rel="prefetch" href="/assets/js/46.08c4dcbb.js"><link rel="prefetch" href="/assets/js/47.0fa3a317.js"><link rel="prefetch" href="/assets/js/48.15f53959.js"><link rel="prefetch" href="/assets/js/49.f9b62975.js"><link rel="prefetch" href="/assets/js/5.49ddc4eb.js"><link rel="prefetch" href="/assets/js/50.5d678fce.js"><link rel="prefetch" href="/assets/js/51.f07100da.js"><link rel="prefetch" href="/assets/js/52.25782c95.js"><link rel="prefetch" href="/assets/js/53.1151ca9a.js"><link rel="prefetch" href="/assets/js/54.86132d90.js"><link rel="prefetch" href="/assets/js/55.5e273c50.js"><link rel="prefetch" href="/assets/js/56.94d89ae7.js"><link rel="prefetch" href="/assets/js/57.ff4f6ce5.js"><link rel="prefetch" href="/assets/js/58.d6bba7bf.js"><link rel="prefetch" href="/assets/js/59.fd39aa8f.js"><link rel="prefetch" href="/assets/js/6.73ba3b93.js"><link rel="prefetch" href="/assets/js/60.3b547209.js"><link rel="prefetch" href="/assets/js/61.c2746621.js"><link rel="prefetch" href="/assets/js/62.c7246830.js"><link rel="prefetch" href="/assets/js/63.8cf018aa.js"><link rel="prefetch" href="/assets/js/64.5982f68e.js"><link rel="prefetch" href="/assets/js/65.6a323f0b.js"><link rel="prefetch" href="/assets/js/66.df6d599d.js"><link rel="prefetch" href="/assets/js/67.5c26c24c.js"><link rel="prefetch" href="/assets/js/68.e53dceea.js"><link rel="prefetch" href="/assets/js/69.65ee4851.js"><link rel="prefetch" href="/assets/js/7.541920c5.js"><link rel="prefetch" href="/assets/js/70.4bfafea4.js"><link rel="prefetch" href="/assets/js/71.b4f496a8.js"><link rel="prefetch" href="/assets/js/72.1b1ffea6.js"><link rel="prefetch" href="/assets/js/73.8929e1c4.js"><link rel="prefetch" href="/assets/js/74.d3c5fcad.js"><link rel="prefetch" href="/assets/js/75.9d01a456.js"><link rel="prefetch" href="/assets/js/76.3149b796.js"><link rel="prefetch" href="/assets/js/77.3abe6bd4.js"><link rel="prefetch" href="/assets/js/78.ae477312.js"><link rel="prefetch" href="/assets/js/79.00837d52.js"><link rel="prefetch" href="/assets/js/8.a50175f7.js"><link rel="prefetch" href="/assets/js/80.d626622b.js"><link rel="prefetch" href="/assets/js/81.ad2df06d.js"><link rel="prefetch" href="/assets/js/82.9ac0d88a.js"><link rel="prefetch" href="/assets/js/83.b23219b4.js"><link rel="prefetch" href="/assets/js/84.55f2741f.js"><link rel="prefetch" href="/assets/js/85.33b715e5.js"><link rel="prefetch" href="/assets/js/86.85aea4fa.js"><link rel="prefetch" href="/assets/js/87.6fd2f3fa.js"><link rel="prefetch" href="/assets/js/88.a9ea00b4.js"><link rel="prefetch" href="/assets/js/89.7e58e472.js"><link rel="prefetch" href="/assets/js/9.83acbe8c.js"><link rel="prefetch" href="/assets/js/90.e15687d5.js"><link rel="prefetch" href="/assets/js/91.026b108a.js"><link rel="prefetch" href="/assets/js/92.840afd12.js"><link rel="prefetch" href="/assets/js/93.00439ef2.js"><link rel="prefetch" href="/assets/js/94.6c994a63.js"><link rel="prefetch" href="/assets/js/95.e3dd6367.js"><link rel="prefetch" href="/assets/js/96.cbe1207c.js"><link rel="prefetch" href="/assets/js/97.34584059.js"><link rel="prefetch" href="/assets/js/98.9b2de21d.js"><link rel="prefetch" href="/assets/js/99.95d4993f.js">
    <link rel="stylesheet" href="/assets/css/0.styles.154256f1.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="layout-wrapper"><!----> <div class="theme-container"><header class="navbar ele-navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/manong.jpg" alt="小马过河" class="logo"> <span class="site-name can-hide">小马过河</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><!----> <a href="/" class="nav-link">
  首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="导航" class="dropdown-title"><span class="title">导航</span> <span class="arrow down"></span></button> <button type="button" aria-label="导航" class="mobile-dropdown-title"><span class="title">导航</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/nav/nav.html" class="nav-link">
  常用站点
</a></li><li class="dropdown-item"><!----> <a href="/nav/web.html" class="nav-link">
  前端站点
</a></li><li class="dropdown-item"><!----> <a href="/nav/afterEnd.html" class="nav-link">
  后端站点
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><span class="title">前端</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端" class="mobile-dropdown-title"><span class="title">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          CSS+HTML系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/csshtml/css-formatContent.html" class="nav-link">
  CSS格式化上下文
</a></li><li class="dropdown-subitem"><a href="/web/csshtml/css-bfc.html" class="nav-link">
  CSS的BFC
</a></li></ul></li><li class="dropdown-item"><h4>
          JS系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/js/js-prototype.html" class="nav-link">
  JS-原型与原型链
</a></li><li class="dropdown-subitem"><a href="/web/js/js-context.html" class="nav-link">
  JS-执行上下文
</a></li></ul></li><li class="dropdown-item"><h4>
          Vue2系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/vue/mvvm.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  Vue响应式
</a></li></ul></li><li class="dropdown-item"><h4>
          常见面试题
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/question/css.html" class="nav-link">
  CSS面试题
</a></li><li class="dropdown-subitem"><a href="/web/question/vue.html" class="nav-link">
  Vue2.x面试题
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Java" class="dropdown-title"><span class="title">Java</span> <span class="arrow down"></span></button> <button type="button" aria-label="Java" class="mobile-dropdown-title"><span class="title">Java</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          基础系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/basics/know.html" class="nav-link">
  Java初识
</a></li><li class="dropdown-subitem"><a href="/java/basics/number.html" class="nav-link">
  Java数字
</a></li><li class="dropdown-subitem"><a href="/java/basics/string.html" class="nav-link">
  Java字符串
</a></li></ul></li><li class="dropdown-item"><h4>
          集合
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/collection/collection.html" class="nav-link">
  Collection集合
</a></li><li class="dropdown-subitem"><a href="/java/collection/list.html" class="nav-link">
  List集合
</a></li></ul></li><li class="dropdown-item"><h4>
          IO操作
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/io/" class="nav-link">
  IO初识
</a></li></ul></li><li class="dropdown-item"><h4>
          网络编程
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/network/ip.html" class="nav-link">
  IP操作
</a></li></ul></li><li class="dropdown-item"><h4>
          JDBC操作
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/jdbc/mysql-connect.html" class="nav-link">
  MySQL操作
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><span class="title">数据库</span> <span class="arrow down"></span></button> <button type="button" aria-label="数据库" class="mobile-dropdown-title"><span class="title">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          MySQL系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/database/mysql/init.html" class="nav-link">
  常用语法
</a></li><li class="dropdown-subitem"><a href="/database/mysql/data-type.html" class="nav-link">
  数据类型
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="设计模式" class="dropdown-title"><span class="title">设计模式</span> <span class="arrow down"></span></button> <button type="button" aria-label="设计模式" class="mobile-dropdown-title"><span class="title">设计模式</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/designMode/observer.html" class="nav-link">
  观察者模式
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="运维/工具" class="dropdown-title"><span class="title">运维/工具</span> <span class="arrow down"></span></button> <button type="button" aria-label="运维/工具" class="mobile-dropdown-title"><span class="title">运维/工具</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          Maven
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/tools/maven/" class="nav-link">
  初识
</a></li></ul></li><li class="dropdown-item"><h4>
          Tomcat
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/tools/tomcat/" class="nav-link">
  初识
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="English" class="dropdown-title"><span class="title">English</span> <span class="arrow down"></span></button> <button type="button" aria-label="English" class="mobile-dropdown-title"><span class="title">English</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          英语读音
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/pronunciation/phonogram.html" class="nav-link">
  音标
</a></li></ul></li><li class="dropdown-item"><h4>
          英语单词
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/word/call.html" class="nav-link">
  电话
</a></li><li class="dropdown-subitem"><a href="/english/word/daily-life.html" class="nav-link">
  日常生活
</a></li><li class="dropdown-subitem"><a href="/english/word/animal.html" class="nav-link">
  动物
</a></li></ul></li><li class="dropdown-item"><h4>
          英语语法
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/grammar/sentence.html" class="nav-link">
  句子成分
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Study" class="dropdown-title"><span class="title">Study</span> <span class="arrow down"></span></button> <button type="button" aria-label="Study" class="mobile-dropdown-title"><span class="title">Study</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/study/computers/" class="nav-link">
  计算机基础
</a></li><li class="dropdown-item"><!----> <a href="/study/web/" class="nav-link">
  前端知识路线
</a></li><li class="dropdown-item"><!----> <a href="/study/java/" class="nav-link">
  Java知识路线
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Self" class="dropdown-title"><span class="title">Self</span> <span class="arrow down"></span></button> <button type="button" aria-label="Self" class="mobile-dropdown-title"><span class="title">Self</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/self/work/" class="nav-link">
  工作
</a></li></ul></div> <!----></div> <!----></nav> <div class="loginItem"><!----></div></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><!----> <a href="/" class="nav-link">
  首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="导航" class="dropdown-title"><span class="title">导航</span> <span class="arrow down"></span></button> <button type="button" aria-label="导航" class="mobile-dropdown-title"><span class="title">导航</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/nav/nav.html" class="nav-link">
  常用站点
</a></li><li class="dropdown-item"><!----> <a href="/nav/web.html" class="nav-link">
  前端站点
</a></li><li class="dropdown-item"><!----> <a href="/nav/afterEnd.html" class="nav-link">
  后端站点
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端" class="dropdown-title"><span class="title">前端</span> <span class="arrow down"></span></button> <button type="button" aria-label="前端" class="mobile-dropdown-title"><span class="title">前端</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          CSS+HTML系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/csshtml/css-formatContent.html" class="nav-link">
  CSS格式化上下文
</a></li><li class="dropdown-subitem"><a href="/web/csshtml/css-bfc.html" class="nav-link">
  CSS的BFC
</a></li></ul></li><li class="dropdown-item"><h4>
          JS系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/js/js-prototype.html" class="nav-link">
  JS-原型与原型链
</a></li><li class="dropdown-subitem"><a href="/web/js/js-context.html" class="nav-link">
  JS-执行上下文
</a></li></ul></li><li class="dropdown-item"><h4>
          Vue2系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/vue/mvvm.html" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  Vue响应式
</a></li></ul></li><li class="dropdown-item"><h4>
          常见面试题
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/web/question/css.html" class="nav-link">
  CSS面试题
</a></li><li class="dropdown-subitem"><a href="/web/question/vue.html" class="nav-link">
  Vue2.x面试题
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Java" class="dropdown-title"><span class="title">Java</span> <span class="arrow down"></span></button> <button type="button" aria-label="Java" class="mobile-dropdown-title"><span class="title">Java</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          基础系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/basics/know.html" class="nav-link">
  Java初识
</a></li><li class="dropdown-subitem"><a href="/java/basics/number.html" class="nav-link">
  Java数字
</a></li><li class="dropdown-subitem"><a href="/java/basics/string.html" class="nav-link">
  Java字符串
</a></li></ul></li><li class="dropdown-item"><h4>
          集合
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/collection/collection.html" class="nav-link">
  Collection集合
</a></li><li class="dropdown-subitem"><a href="/java/collection/list.html" class="nav-link">
  List集合
</a></li></ul></li><li class="dropdown-item"><h4>
          IO操作
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/io/" class="nav-link">
  IO初识
</a></li></ul></li><li class="dropdown-item"><h4>
          网络编程
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/network/ip.html" class="nav-link">
  IP操作
</a></li></ul></li><li class="dropdown-item"><h4>
          JDBC操作
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/java/jdbc/mysql-connect.html" class="nav-link">
  MySQL操作
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="数据库" class="dropdown-title"><span class="title">数据库</span> <span class="arrow down"></span></button> <button type="button" aria-label="数据库" class="mobile-dropdown-title"><span class="title">数据库</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          MySQL系列
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/database/mysql/init.html" class="nav-link">
  常用语法
</a></li><li class="dropdown-subitem"><a href="/database/mysql/data-type.html" class="nav-link">
  数据类型
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="设计模式" class="dropdown-title"><span class="title">设计模式</span> <span class="arrow down"></span></button> <button type="button" aria-label="设计模式" class="mobile-dropdown-title"><span class="title">设计模式</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/designMode/observer.html" class="nav-link">
  观察者模式
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="运维/工具" class="dropdown-title"><span class="title">运维/工具</span> <span class="arrow down"></span></button> <button type="button" aria-label="运维/工具" class="mobile-dropdown-title"><span class="title">运维/工具</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          Maven
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/tools/maven/" class="nav-link">
  初识
</a></li></ul></li><li class="dropdown-item"><h4>
          Tomcat
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/tools/tomcat/" class="nav-link">
  初识
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="English" class="dropdown-title"><span class="title">English</span> <span class="arrow down"></span></button> <button type="button" aria-label="English" class="mobile-dropdown-title"><span class="title">English</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>
          英语读音
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/pronunciation/phonogram.html" class="nav-link">
  音标
</a></li></ul></li><li class="dropdown-item"><h4>
          英语单词
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/word/call.html" class="nav-link">
  电话
</a></li><li class="dropdown-subitem"><a href="/english/word/daily-life.html" class="nav-link">
  日常生活
</a></li><li class="dropdown-subitem"><a href="/english/word/animal.html" class="nav-link">
  动物
</a></li></ul></li><li class="dropdown-item"><h4>
          英语语法
        </h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/english/grammar/sentence.html" class="nav-link">
  句子成分
</a></li></ul></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Study" class="dropdown-title"><span class="title">Study</span> <span class="arrow down"></span></button> <button type="button" aria-label="Study" class="mobile-dropdown-title"><span class="title">Study</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/study/computers/" class="nav-link">
  计算机基础
</a></li><li class="dropdown-item"><!----> <a href="/study/web/" class="nav-link">
  前端知识路线
</a></li><li class="dropdown-item"><!----> <a href="/study/java/" class="nav-link">
  Java知识路线
</a></li></ul></div> <!----></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="Self" class="dropdown-title"><span class="title">Self</span> <span class="arrow down"></span></button> <button type="button" aria-label="Self" class="mobile-dropdown-title"><span class="title">Self</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/self/work/" class="nav-link">
  工作
</a></li></ul></div> <!----></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>CSS+HTML系列</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>JS系列</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>Vue2.x系列</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/web/vue/mvvm.html" aria-current="page" class="active sidebar-link">Vue-响应式原理</a></li><li><a href="/web/vue/computed.html" class="sidebar-link">Vue-Computed实现原理</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Vue3.x系列</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>常见面试题</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="main"><div class="content"><div class="theme-default-content content__default"><h1 id="vue-响应式原理"><a href="#vue-响应式原理" class="header-anchor">#</a> Vue-响应式原理</h1> <p></p><div class="table-of-contents"><ul><li><a href="#前言">前言</a></li><li><a href="#原理">原理</a></li><li><a href="#实现">实现</a><ul><li><a href="#监听器observer">监听器Observer</a></li><li><a href="#订阅者wathcer">订阅者Wathcer</a></li><li><a href="#订阅器">订阅器</a></li><li><a href="#解析器compile">解析器Compile</a></li><li><a href="#vue构造函数">Vue构造函数</a></li><li><a href="#使用">使用</a></li></ul></li><li><a href="#vue2-x响应式缺点">Vue2.X响应式缺点</a></li></ul></div><p></p> <p>🐴</p> <h2 id="前言"><a href="#前言" class="header-anchor">#</a> 前言</h2> <p><code>Vue2.x</code>已经用来好几年了，这里再次温习一下<code>Vue2.x</code>的响应式原理。</p> <ul><li>下面全部代码：<a href="https://gitee.com/individual_event/blogs-code/tree/master/vue/vue2.x/mvvm" target="_blank" rel="noopener noreferrer">访问这里<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul> <h2 id="原理"><a href="#原理" class="header-anchor">#</a> 原理</h2> <p><code>Vue2.x</code>响应式是使用了<code>Object.defineProperty</code>劫持数据 + <a href="/designMode/observer.html">发布订阅者模式</a> 。</p> <p><code>Vue2.x</code>的响应式大致可以描述成这样：</p> <ol><li>创建一个观察者<code>Observer</code>,在初始化时，将<code>Vue data</code>中的数据添加<code>get</code>和<code>set</code>方法。来实现对数据变化的监听。</li> <li>实现订阅者<code>Watcher</code>, <code>Watcher</code>具有更新函数，用来通知更新视图</li> <li>实现一个订阅器<code>Dep</code>，用来存储订阅者。该订阅器具有添加订阅者<code>addSub</code>方法和通知订阅者<code>notify</code>方法。</li> <li>实现一个解析器<code>Complie</code>，该方法主要作用就是更新视图，将视图节点与数据进行绑定（<code>Observer</code>与<code>Watcher</code>进行关联）。</li> <li><code>Vue</code>实例的实现，初识化数据，执行各个方法，将<code>data</code>数据代理到<code>Vue</code>实例上。</li></ol> <p>当<code>new Vue()</code>时，首先初识化<code>data</code>中的数据，调用观察者<code>Observer</code>，给<code>data</code>数据添加<code>get</code>和<code>set</code>方法。然后将数据代理绑定到<code>Vue</code>实例上。</p> <p>初始化视图时调用<code>Complie</code>, 遍历<code>DOM</code>元素，根据正则匹配<code>{{}}</code>中的数据，替换真正的<code>data</code>中的值，并创建订阅者<code>Watcher</code>。当读取<code>data</code>中的值时，就会调用该值的<code>get</code>方法。此时将订阅者添加到订阅器<code>Dep</code>中。至此响应式的基础大致过程完成。</p> <h2 id="实现"><a href="#实现" class="header-anchor">#</a> 实现</h2> <p>根据上面提到的流程我们要是实现基础的响应式，需要实现下面方法</p> <ul><li>观察者<code>Observer</code></li> <li>订阅者<code>Watche</code></li> <li>订阅器<code>Dep</code></li> <li>解析器<code>Complie</code></li> <li><code>Vue</code>构造函数</li></ul> <p>下面我们简单实现一下上述过程</p> <h3 id="监听器observer"><a href="#监听器observer" class="header-anchor">#</a> 监听器Observer</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Observer</span><span class="token punctuation">{</span>
  <span class="token comment">// 初始化</span>
  <span class="token function">init</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>data <span class="token operator">||</span> <span class="token keyword">typeof</span> data <span class="token operator">!==</span> <span class="token string">'object'</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
       <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">defineReactive</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span>key<span class="token punctuation">,</span>data<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 为所有属性添加getter setter 方法</span>
  <span class="token function">defineReactive</span><span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span>key<span class="token punctuation">,</span>val</span><span class="token punctuation">)</span><span class="token punctuation">{</span>

    <span class="token comment">// 递归添加get set</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>data<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>

    <span class="token keyword">const</span> dep <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Dep</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span>key<span class="token punctuation">,</span><span class="token punctuation">{</span>
      enumerable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 可以枚举</span>
      configurable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 可以设置</span>
      <span class="token function">set</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">// 新值和旧值是否相等</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>val <span class="token operator">===</span> newValue<span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>

        val <span class="token operator">=</span> newValue<span class="token punctuation">;</span>
        dep<span class="token punctuation">.</span><span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 通知订阅者，数据有变化</span>

      <span class="token punctuation">}</span><span class="token punctuation">,</span>
      <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        Dep<span class="token punctuation">.</span>target <span class="token operator">&amp;&amp;</span> dep<span class="token punctuation">.</span><span class="token function">addSub</span><span class="token punctuation">(</span>Dep<span class="token punctuation">.</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 存储订阅者</span>
        <span class="token keyword">return</span> val<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>上面我们实现了监听器<code>Observer</code>的主要功能。可以测试一下：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> Obj <span class="token operator">=</span> <span class="token punctuation">{</span>
  a<span class="token operator">:</span><span class="token number">1</span><span class="token punctuation">,</span>
  b<span class="token operator">:</span><span class="token number">2</span>
<span class="token punctuation">}</span>

<span class="token keyword">const</span> Observer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Observer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

Observer<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span>Obj<span class="token punctuation">)</span><span class="token punctuation">;</span>
Obj<span class="token punctuation">.</span>a<span class="token punctuation">;</span>
</code></pre></div><h3 id="订阅者wathcer"><a href="#订阅者wathcer" class="header-anchor">#</a> 订阅者Wathcer</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Watcher</span><span class="token punctuation">{</span>
  <span class="token comment">// vm vue实例</span>
  <span class="token comment">// exper vue模板如{{a}} {{obj.b}}</span>
  <span class="token comment">// callback 更新视图得回调函数，</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>expr<span class="token punctuation">,</span>callback</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>vm <span class="token operator">=</span> vm<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>expr <span class="token operator">=</span> expr<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>callback <span class="token operator">=</span> callback<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getVal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>  
  
  <span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 更新函数</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
   
  <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 执行</span>
    <span class="token keyword">const</span> value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getDataVal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> oldValue <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>value<span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>value <span class="token operator">!==</span> oldValue<span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">callback</span><span class="token punctuation">.</span><span class="token function">call</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token function">getVal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     Dep<span class="token punctuation">.</span>target <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">;</span>

     <span class="token comment">// 这里会调用 get 方法，将订阅者添加到 订阅容器中</span>
     <span class="token keyword">const</span>  value <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getDataVal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     Dep<span class="token punctuation">.</span>target <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>

     <span class="token keyword">return</span> value<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 获取data中的值</span>
  <span class="token function">getDataVal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> valAry <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>expr<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> valAry<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span>next</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
       <span class="token keyword">return</span> prev<span class="token punctuation">[</span>next<span class="token punctuation">]</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">.</span>$data<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>订阅者<code>Watcher</code>中，<code>getVal</code>方法主要的作用是，当<code>Watcher</code>创建时，立即读取<code>data</code>数据中的数据，调用<code>getVal</code>方法，该方法将<code>Dep.target</code>变量设置成当前<code>Watcher</code>实例, 然后调用<code>getDataVal</code>获取<code>data</code>中对应得值， 此时会触发所读取值得<code>get</code>方法。在<code>get</code>方法中判断<code>Dep.target</code>存在时，调用订阅器得<code>addSub</code>方法，将订阅者添加到订阅器中。下面是订阅器得代码</p> <h3 id="订阅器"><a href="#订阅器" class="header-anchor">#</a> 订阅器</h3> <p>订阅器代码很少，但是很重要。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Dep</span><span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>subs <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token comment">// 用于存储订阅者</span>
  <span class="token punctuation">}</span>

  <span class="token function">addSub</span><span class="token punctuation">(</span><span class="token parameter">sub</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 添加订阅者</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>subs<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>sub<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">notify</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 通知订阅者</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>subs<span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">sub</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      sub<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="解析器compile"><a href="#解析器compile" class="header-anchor">#</a> 解析器Compile</h3> <p>解析器<code>Complie</code>的主要作用就是解析<code>Vue</code>模板，连接视图和数据，为订阅者<code>Watcher</code>和观察者 <code>Observer</code>搭建一个桥梁。</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">Complie</span><span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>el</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>vm <span class="token operator">=</span> vm<span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>el <span class="token operator">=</span> el<span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span>fragment <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">nodeToFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">complieEle</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>fragment<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>fragment<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 遍历Dom元素，将其添加到Dom片段中</span>
  <span class="token function">nodeToFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span> 
    <span class="token keyword">const</span> fragment <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">createDocumentFragment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">let</span> child <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">.</span>firstChild<span class="token punctuation">;</span>
    <span class="token keyword">while</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">{</span>
      fragment<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span>
      child <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>el<span class="token punctuation">.</span>firstChild<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> fragment<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 递归编译元素</span>
  <span class="token function">complieEle</span><span class="token punctuation">(</span><span class="token parameter">el</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token comment">// 获取el 子元素集合</span>
     <span class="token keyword">const</span> childNodesList <span class="token operator">=</span> el<span class="token punctuation">.</span>childNodes<span class="token punctuation">;</span>
     <span class="token keyword">const</span> reg <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\{\{([^}]+)\}\}</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">;</span>
     
     <span class="token punctuation">[</span><span class="token operator">...</span>childNodesList<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
        <span class="token keyword">const</span> text <span class="token operator">=</span> node<span class="token punctuation">.</span>textContent<span class="token punctuation">;</span>
        <span class="token comment">// 判断是否符合{{}}指令</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isTextNode</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> reg<span class="token punctuation">.</span><span class="token function">test</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 文本节点</span>
          CompileUtil<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isElementNode</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 元素节点</span>
          <span class="token comment">// 获取dom节点所有的属性</span>
          <span class="token keyword">const</span> attrs <span class="token operator">=</span> node<span class="token punctuation">.</span>attributes<span class="token punctuation">;</span> 
          Array<span class="token punctuation">.</span><span class="token function">from</span><span class="token punctuation">(</span>attrs<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">attr</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
            <span class="token keyword">const</span> attrName <span class="token operator">=</span> attr<span class="token punctuation">.</span>name<span class="token punctuation">;</span>
            
            <span class="token comment">// 判断是否为 v- 指令 如 v-model v-html v-text等</span>
            <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isDirective</span><span class="token punctuation">(</span>attrName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
               <span class="token keyword">const</span> attrVal <span class="token operator">=</span> attr<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
               <span class="token keyword">const</span> <span class="token punctuation">[</span><span class="token punctuation">,</span>type<span class="token punctuation">]</span> <span class="token operator">=</span> attrName<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;-&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
               CompileUtil<span class="token punctuation">[</span>type<span class="token punctuation">]</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>attrVal<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>
       
          <span class="token comment">// 对子节点进行递归</span>
          <span class="token keyword">if</span><span class="token punctuation">(</span>node<span class="token punctuation">.</span>childNodes <span class="token operator">&amp;&amp;</span> node<span class="token punctuation">.</span>childNodes<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">complieEle</span><span class="token punctuation">(</span>node<span class="token punctuation">)</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        
     <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 是否是指令</span>
  <span class="token function">isDirective</span><span class="token punctuation">(</span><span class="token parameter">attr</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token keyword">return</span> attr<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">&quot;v-&quot;</span><span class="token punctuation">)</span> <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 处理模板 {{}} 数据</span>
  <span class="token function">compileText</span><span class="token punctuation">(</span><span class="token parameter">node<span class="token punctuation">,</span>key</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token keyword">const</span> text <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">.</span>$data<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>

     <span class="token comment">// 初始化视图</span>
     <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">updateView</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span>text<span class="token punctuation">)</span><span class="token punctuation">;</span>

     <span class="token comment">// 创建订阅者 并绑定回调函数</span>
     <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>vm<span class="token punctuation">,</span>key<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">value</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
       <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">updateView</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span>value<span class="token punctuation">)</span>
     <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 更新视图</span>
  <span class="token function">updateView</span><span class="token punctuation">(</span><span class="token parameter">node<span class="token punctuation">,</span>value</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token number">111</span><span class="token punctuation">,</span>node<span class="token punctuation">.</span>textContent<span class="token punctuation">)</span>
    <span class="token comment">// node.textContent = typeof value === 'undefined' ? '' : value;</span>
  <span class="token punctuation">}</span>
 

  <span class="token comment">// 判断是否为文本节点textNode</span>
  <span class="token function">isTextNode</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
   <span class="token keyword">return</span> node<span class="token punctuation">.</span>nodeType <span class="token operator">===</span> <span class="token number">3</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 判断是否为元素节点</span>
  <span class="token function">isElementNode</span><span class="token punctuation">(</span><span class="token parameter">node</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">return</span> node<span class="token punctuation">.</span>nodeType <span class="token operator">===</span> <span class="token number">1</span><span class="token punctuation">;</span>
   <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre></div><p><code>Compile</code>初识化时，将遍历<code>DOM</code>节点，使用<code>createDocumentFragment</code>创建节点碎片。然后我们通过<code>complieEle</code>方法递归遍历元素，将元素中得指令，以及<code>{{}}</code>进行解析。解析到<code>Vue</code>得响应式数据时创建订阅者<code>Watcher</code>，并传入响应得更新回调函数。</p> <p>另外我们将常用得解析方法封装到了<code>CompileUtil</code>中，代码如下：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// 解析器常用方法</span>
<span class="token keyword">const</span> CompileUtil <span class="token operator">=</span> <span class="token punctuation">{</span>
   RegText<span class="token operator">:</span><span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">\{\{([^}]+)\}\}</span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span>
   <span class="token function">getVal</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>expr</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
     <span class="token comment">/**
      * 得到data中对应的数据,exper 可能为 obj.a.b 形式
      * 需要拿到data中的数据
      * {
      *   obj:{
      *      a:{b:1}
      *   }
      * }
      */</span>
     <span class="token keyword">const</span> valAry <span class="token operator">=</span> expr<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token keyword">return</span> valAry<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span>next</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
        <span class="token keyword">return</span> prev<span class="token punctuation">[</span>next<span class="token punctuation">]</span>
     <span class="token punctuation">}</span><span class="token punctuation">,</span>vm<span class="token punctuation">)</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token function">setVal</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>expr<span class="token punctuation">,</span>val</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> valAry <span class="token operator">=</span> expr<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    valAry<span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">prev<span class="token punctuation">,</span>next<span class="token punctuation">,</span>index</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token punctuation">(</span>index <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">===</span> valAry<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">{</span>
        prev<span class="token punctuation">[</span>next<span class="token punctuation">]</span> <span class="token operator">=</span> val<span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
      <span class="token keyword">return</span> prev<span class="token punctuation">[</span>next<span class="token punctuation">]</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>vm<span class="token punctuation">)</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token comment">//处理模板 {{}} 数据</span>
   <span class="token function">text</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>exper</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 编译text</span>
     <span class="token keyword">const</span> val <span class="token operator">=</span> exper<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>RegText<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>arg</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
          <span class="token comment">// arg 为匹配的数据信息数组</span>
          <span class="token comment">// 创建观察者</span>
          <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>arg<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
              <span class="token keyword">const</span> val <span class="token operator">=</span> exper<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>RegText<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>arg</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
                <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getVal</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>arg<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
              <span class="token punctuation">}</span><span class="token punctuation">)</span>
            
              <span class="token keyword">this</span><span class="token punctuation">.</span>updater<span class="token punctuation">.</span><span class="token function">textUpdater</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span>val<span class="token punctuation">)</span>
          <span class="token punctuation">}</span><span class="token punctuation">)</span>

        <span class="token comment">// 创建订阅者 并绑定回调函数</span>
        <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getVal</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>arg<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
     <span class="token punctuation">}</span><span class="token punctuation">)</span>

   
     <span class="token keyword">this</span><span class="token punctuation">.</span>updater<span class="token punctuation">.</span><span class="token function">textUpdater</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span>val<span class="token punctuation">)</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>
   <span class="token comment">// 处理v-model数据</span>
   <span class="token function">model</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>exper</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token keyword">const</span> val <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getVal</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>exper<span class="token punctuation">)</span><span class="token punctuation">;</span>
      
      <span class="token comment">// 创建订阅者</span>
      <span class="token keyword">new</span> <span class="token class-name">Watcher</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>exper<span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>updater<span class="token punctuation">.</span><span class="token function">modelUpdater</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getVal</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>exper<span class="token punctuation">)</span><span class="token punctuation">)</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span>updater<span class="token punctuation">.</span><span class="token function">modelUpdater</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span>val<span class="token punctuation">)</span>
      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">formChange</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>exper<span class="token punctuation">)</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>

   <span class="token function">formChange</span><span class="token punctuation">(</span><span class="token parameter">vm<span class="token punctuation">,</span>node<span class="token punctuation">,</span>exper</span><span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 表单input事件</span>
     
     node<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">&quot;input&quot;</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">e</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
       <span class="token keyword">const</span> value <span class="token operator">=</span> e<span class="token punctuation">.</span>target<span class="token punctuation">.</span>value<span class="token punctuation">;</span>
       <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">setVal</span><span class="token punctuation">(</span>vm<span class="token punctuation">,</span>exper<span class="token punctuation">,</span>value<span class="token punctuation">)</span>
       
     <span class="token punctuation">}</span><span class="token punctuation">)</span>
   <span class="token punctuation">}</span><span class="token punctuation">,</span>

   updater<span class="token operator">:</span><span class="token punctuation">{</span>
     <span class="token function">textUpdater</span><span class="token punctuation">(</span><span class="token parameter">node<span class="token punctuation">,</span>value</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
       node<span class="token punctuation">.</span>textContent <span class="token operator">=</span>  value<span class="token punctuation">;</span>
     <span class="token punctuation">}</span><span class="token punctuation">,</span>
     <span class="token function">modelUpdater</span><span class="token punctuation">(</span><span class="token parameter">node<span class="token punctuation">,</span>value</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
       node<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token keyword">typeof</span> value <span class="token operator">===</span> <span class="token string">'undefined'</span> <span class="token operator">?</span> <span class="token string">''</span> <span class="token operator">:</span> value<span class="token punctuation">;</span>
     <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="vue构造函数"><a href="#vue构造函数" class="header-anchor">#</a> Vue构造函数</h3> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">class</span> <span class="token class-name">NVue</span><span class="token punctuation">{</span>
  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">option</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> <span class="token punctuation">{</span>data<span class="token punctuation">}</span> <span class="token operator">=</span>  option<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>option <span class="token operator">=</span> option<span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>$data <span class="token operator">=</span> <span class="token keyword">typeof</span> data <span class="token operator">===</span> <span class="token string">'object'</span><span class="token operator">?</span>data<span class="token operator">:</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>$el <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>

    <span class="token comment">// 初始化数据</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">initState</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token comment">// 代理数据到vue实例上</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">proxyData</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>$data<span class="token punctuation">)</span>

    <span class="token comment">// 渲染页面</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>$el <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>option<span class="token punctuation">.</span>el<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">new</span> <span class="token class-name">Complie</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span><span class="token keyword">this</span><span class="token punctuation">.</span>$el<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 初始化数据</span>
  <span class="token function">initState</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">initData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token comment">// 初始化data数据</span>
  <span class="token function">initData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token keyword">const</span> Obs <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Observer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    Obs<span class="token punctuation">.</span><span class="token function">init</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>$data<span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
  
  <span class="token comment">/**
   *@msg 代理，将数据绑定到Vue实例上 
   */</span>
  <span class="token function">proxyData</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token parameter">key</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
      Object<span class="token punctuation">.</span><span class="token function">defineProperty</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span>key<span class="token punctuation">,</span><span class="token punctuation">{</span>
         enumerable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 可以枚举</span>
         configurable<span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token comment">// 可以设置</span>
         <span class="token function">set</span><span class="token punctuation">(</span>newValue<span class="token punctuation">)</span><span class="token punctuation">{</span>
           data<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> newValue
         <span class="token punctuation">}</span><span class="token punctuation">,</span>
         <span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token keyword">return</span> data<span class="token punctuation">[</span>key<span class="token punctuation">]</span> 
         <span class="token punctuation">}</span>
      <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><h3 id="使用"><a href="#使用" class="header-anchor">#</a> 使用</h3> <div class="language-html extra-class"><pre class="language-html"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>main<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">v-model</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>a<span class="token punctuation">&quot;</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>text<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">&gt;</span></span>hello {{a}} {{obj.b}}<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">&gt;</span></span>
  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>./index.js<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
  <span class="token keyword">let</span> main <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;main&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
  <span class="token keyword">const</span> vueObj <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">NVue</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    el<span class="token operator">:</span><span class="token string">&quot;#main&quot;</span><span class="token punctuation">,</span>
    <span class="token function">data</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
      <span class="token keyword">return</span> <span class="token punctuation">{</span>
        a<span class="token operator">:</span><span class="token string">&quot;小明&quot;</span><span class="token punctuation">,</span>
        obj<span class="token operator">:</span><span class="token punctuation">{</span>
          b<span class="token operator">:</span><span class="token string">&quot;小红&quot;</span><span class="token punctuation">,</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

  console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>vueObj<span class="token punctuation">)</span>
  <span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">=&gt;</span><span class="token punctuation">{</span>
    vueObj<span class="token punctuation">.</span>obj<span class="token punctuation">.</span>b <span class="token operator">=</span> <span class="token string">&quot;1111&quot;</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token number">2000</span><span class="token punctuation">)</span>

</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
</code></pre></div><h2 id="vue2-x响应式缺点"><a href="#vue2-x响应式缺点" class="header-anchor">#</a> Vue2.X响应式缺点</h2> <p><code>Vue2.x</code>的响应式主要依赖于<code>Object.definedProprety</code>实现的。然而<code>Object.definedProprety</code>具有一下弊端</p> <ul><li>不支持<code>IE8</code></li> <li>无法监听到对象属性的动态添加和删除</li> <li>无法监听到数组下标和length长度的变化</li></ul> <p>当然上边问题，<code>vue2.x</code> 通过 <code>$set</code>方法进行的补充修复</p> <p><strong>参考文献</strong></p> <ul><li><a href="https://www.cnblogs.com/canfoo/p/6891868.html" target="_blank" rel="noopener noreferrer">vue的双向绑定原理及实现<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://www.jianshu.com/p/743166a8968c" target="_blank" rel="noopener noreferrer">vue模板渲染--compile<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://segmentfault.com/a/1190000006599500" target="_blank" rel="noopener noreferrer">剖析Vue原理&amp;实现双向绑定MVVM<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li></ul></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">最近更新时间:</span> <span class="time">7/2/2021, 11:27:27 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
      ←
      <a href="/web/js/js-new.html" class="prev">
        JS-new操作符
      </a></span> <span class="next"><a href="/web/vue/computed.html">
        Vue-Computed实现原理
      </a>
      →
    </span></p></div></div> <div class="floatSilder hidden-sm-and-down"><div class="floatSilderWrapper" data-v-4100c7a9><div class="topTitle" data-v-4100c7a9>Vue-响应式原理</div> <div class="contentNav" data-v-4100c7a9><ul class="nav" data-v-4100c7a9><li class="title" data-v-4100c7a9><a href="#前言" data-v-4100c7a9>前言</a></li><li class="title" data-v-4100c7a9><a href="#原理" data-v-4100c7a9>原理</a></li><li class="title" data-v-4100c7a9><a href="#实现" data-v-4100c7a9>实现</a></li><li class="subTitle" data-v-4100c7a9><a href="#监听器observer" data-v-4100c7a9>监听器Observer</a></li><li class="subTitle" data-v-4100c7a9><a href="#订阅者wathcer" data-v-4100c7a9>订阅者Wathcer</a></li><li class="subTitle" data-v-4100c7a9><a href="#订阅器" data-v-4100c7a9>订阅器</a></li><li class="subTitle" data-v-4100c7a9><a href="#解析器compile" data-v-4100c7a9>解析器Compile</a></li><li class="subTitle" data-v-4100c7a9><a href="#vue构造函数" data-v-4100c7a9>Vue构造函数</a></li><li class="subTitle" data-v-4100c7a9><a href="#使用" data-v-4100c7a9>使用</a></li><li class="title" data-v-4100c7a9><a href="#vue2-x响应式缺点" data-v-4100c7a9>Vue2.X响应式缺点</a></li></ul></div></div></div></div> </main></div></div><div class="global-ui"><!----></div></div>
    <script src="/assets/js/app.f1a8d465.js" defer></script><script src="/assets/js/2.5bab2b7d.js" defer></script><script src="/assets/js/102.27347aba.js" defer></script>
  </body>
</html>
